package cn.yzj.utils;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.util.Arrays;
import java.util.Optional;

/**
 * Aes 加密工具类
 *
 * @author gzkemays
 * @since 2021/1/25 16:30
 */
public class AesUtils {
  private AesUtils() {}

  private static final String ALGORITHM = "AES";
  private static final String CHARSET_NAME = "UTF-8";

  /**
   * 加密
   *
   * @param data - 加密数据
   * @return - 返回加密后的字符串
   * @throws GeneralSecurityException
   */
  public static String encrypt(String data) throws GeneralSecurityException {
    return encrypt(data, null);
  }

  /**
   * 解密
   *
   * @param data - 加密字符串
   * @return - 解密字符串
   * @throws GeneralSecurityException
   */
  public static String decrypt(String data) throws GeneralSecurityException {
    return decrypt(data, null);
  }

  /**
   * 根据key字符串加密
   *
   * @param data - 加密数据
   * @param key - 盐值
   * @return - 返回加密后的字符串
   * @throws GeneralSecurityException
   */
  public static String encrypt(String data, String key) throws GeneralSecurityException {
    try {
      key = getSecretKey(key);
      Key k = toKey(Base64.decodeBase64(key));
      byte[] raw = k.getEncoded();
      SecretKeySpec secretKeySpec = new SecretKeySpec(raw, ALGORITHM);
      Cipher cipher = Cipher.getInstance(ALGORITHM);
      cipher.init(1, secretKeySpec);
      byte[] bytes = cipher.doFinal(data.getBytes(CHARSET_NAME));
      return Base64.encodeBase64String(bytes);
    } catch (UnsupportedEncodingException e) {
      // 不支持的编码异常
      return data;
    }
  }

  /**
   * 根据key解密字符串
   *
   * @param data - 加密字符串
   * @param key - 盐值
   * @return - 返回解密后的字符串
   * @throws GeneralSecurityException
   */
  public static String decrypt(String data, String key) throws GeneralSecurityException {
    try {
      key = getSecretKey(key);
      Key k = toKey(Base64.decodeBase64(key));
      byte[] raw = k.getEncoded();
      SecretKeySpec secretKeySpec = new SecretKeySpec(raw, ALGORITHM);
      Cipher cipher = Cipher.getInstance(ALGORITHM);
      cipher.init(2, secretKeySpec);
      byte[] baseData = Base64.decodeBase64(data);
      if (baseData.length == 0) {
        throw new RuntimeException("数据无法通过Base64解码");
      }
      byte[] bytes = cipher.doFinal(baseData);
      return new String(bytes, CHARSET_NAME);
    } catch (UnsupportedEncodingException e) {
      // 不支持的编码异常
      return data;
    }
  }

  private static Key toKey(byte[] key) {
    return new SecretKeySpec(key, ALGORITHM);
  }

  private static String getSecretKey(String encrypted) throws UnsupportedEncodingException {
    encrypted = Optional.ofNullable(encrypted).orElse(AesUtils.class.getName());
    byte[] bytes = encrypted.getBytes(CHARSET_NAME);
    bytes = Arrays.copyOf(bytes, 16);
    return Base64.encodeBase64String(bytes);
  }
}
